package traverser;
/*
 * 
 * 
 * 
 */
import java.io.*;
import java.util.HashMap;

public class KeywordTraverserThread extends TrieTraverser {
	// TODO: refactor this - visit currently refers both to the initial
	// prioritization, and to
	// later returning to the link and operating on it.
	public static PriorityParentQueue toVisit;
	public static KeyTracker tracker;
	File result;
	PrintWriter pr;
	public static boolean traverseComplete = false;
	public int workersNumber;

	public KeywordTraverserThread(String startPage, String endPage,int number) {
		super(startPage, endPage);
		workersNumber=number;
		toVisit = new PriorityParentQueue();
		tracker = new KeyTracker(endPage, true);
		result = new File("result.txt");
	}

	
	
	// Compute the keyword priority of a page
	private int computePriority(String page) {

		// Visit a page, check if it's the last link, and compute its priority
		CacheLinkProcessor lp = new CacheLinkProcessor(page);
		// Note: duplicates are important, and order doesn't matter.
		int priority = 0;
		int numLinks = 0;

		for (String link : lp.getLinks()) {
			if (link.equals(endPage)) { // We're done
				traverseComplete = true;
				
			}
			numLinks++;

			for (String key : KeyTracker.splitAndReduce(link)) {
				priority += tracker.priorityOf(key);
			}
		}
		// Normalize priority, so that large pages aren't disproportionately
		// more attractive
		// priority /= numKeys;
		// Note: if we wanted to increase the granularity, we could multiply
		// priority by 10 or something.
		priority *= 100;
		if (numLinks != 0)
			priority /= numLinks;
		else
			priority = 0;

		System.out.println(page + "\t\tpriority " + priority);
		return priority;
	}
	
	
	public int traverse() {
		return traverse(false);
	}

	public int traverse(boolean quiet) {
		System.out.println("Start page: " + startPage);
		System.out.println("End   page: " + endPage);
		System.out.println("Traversing...");
		
		WorkerThreadTry[] thread=new WorkerThreadTry[workersNumber];  //declare threads
		
		for(int k=0;k<workersNumber;k++){
			//Initialize and start all threads. Actually, they will not be running right away,
			//because their fresh flag is still false which means they have not been assigned 
			//a new currentPage.
			thread[k]=new WorkerThreadTry(null,null,endPage,0);   
			thread[k].start();
		}
		// Note: there are some differences between this and other versions of
		// traverse.
		// The big one is that pages are added to the priority queue only AFTER
		// they
		// have been visited, because the only way to get the priority is to
		// visit the page.
		// When all the links on a page have been visited, it is considered
		// exhausted, and
		// only then will it be removed from the queue. Because it remains in
		// the trie
		// (the variable visited), it will not be looked at again.
		//
		// Also, it's important that we use a CacheLinkProcesser (as opposed to
		// a regular
		// old LinkProcesser) here because it allows us to keep pages we've
		// found the
		// priority of in memory, rather than going back out to the server for
		// them.

		int count = 0; // Count of visited pages
		if (endPage.equals(startPage)) {
			return count;
		}

		count++; // The first page counts
    
    	visited.add(startPage, null);
		toVisit.add(startPage, null, computePriority(startPage));

		// Idea: pop a page off the queue and add it to the visited list,
		// get all of the links from that page. If the target page
		// is among them, then stop; otherwise, add all the links
		// to the queue and repeat.
		// String currentPage = "";
		while (toVisit.hasNext()) {
			// Get a page and its priority from the queue
			int currentPriority;
			String currentPage;

			while (true) {
				currentPriority = toVisit.topPriority();
				currentPage = toVisit.pop();
				if (count < 100) { // don't
					break;
				}
				int adjustedPriority = computePriority(currentPage);

				if (adjustedPriority != currentPriority) {
					
					toVisit.add(currentPage, null, adjustedPriority);
				} else {
					break;
				}
			}
			
			
			

			CacheLinkProcessor lp = new CacheLinkProcessor(currentPage);
			lp.removeDuplicates();
			lp.knuthShuffle(); // For now, at least, we'll add links to the
			// queue in a random order
			// TODO: come up with a way to sort links by name priority, or
			// something like that

			System.out.println(count + ": Examining " + currentPage
					+ ", priority " + currentPriority + ", " + lp.count()
					+ " unique links");
            
			
			//Assign threads a new currentPage, and let them start running.
			
			for(int k=0;k<workersNumber;k++){
				thread[k].currentPageSwitch(lp.getLinks(),currentPage,currentPriority);
			}
			
			// Add links to the queue until one has a higher priority than the
			// current page (which in turn
			// should have the highest overall priority)
						
			
			while(toVisit.hasNext()){
				if(WorkerThreadTry.finished==true) {   //check if the threads have found the target page
					traverseComplete=true;
					for(int i=0;i<workersNumber;i++){
						thread[i].stop();
					}
					break;   // stop if found the target Page
				}
				
				//if the threads has not found the target page but found a page with a higher priority,
				// then assign the page to all threads
				else if(WorkerThreadTry.fresh==false){
					int p=toVisit.topPriority();
					String nextLink=toVisit.pop();
					CacheLinkProcessor nlp = new CacheLinkProcessor(nextLink);
					System.out.println((WorkerThreadTry.steps++)+":Examining " + nextLink
							+ ", priority " + p + ", " + lp.count()
							+ " unique links");
					for(int k=0;k<workersNumber;k++)
						thread[k].currentPageSwitch(nlp.getLinks(),nextLink, p);
				}				
			}
			
			
		/*	
	    	for (String link : lp.getLinks()) { // Equivalent to
				// "for (int i = 0; i < links.length; i++)"


				int linkPriority = computePriority(link);
				count++;
				// Note that in computing the priority of link, we must visit
				// it, thus it is added to visited.
				visited.add(link, currentPage);

				

				toVisit.add(link, currentPage, linkPriority);

			}
	    	
	    	*/
		

			// If we are here, then either currentPage was exhausted, or we
			// found a higher priority page
			
		/*	if (toVisit.topPriority() > currentPriority) {
				System.out.println("Found higher priority");
				// If currentPage is not exhausted, then we might want to come
				// back to it later.
				toVisit.add(currentPage, visited.parentOf(currentPage),
						currentPriority);
			} else {
				System.out.println("Exhausted page");
			}
			*/

		}
		// 
		if (traverseComplete) {
			WorkerThreadTry.visited.add(endPage, toVisit.lastParent);
			return count;
		}

		// If we get here, either we have a bug or wikipedia has a closed loop.
		else {System.out.println("Looks like we exhausted wikipedia.");
		      return -1;
		}

	}

	/**
	 * @param args
	 */

	public static void main(String[] args) {
		String start, end;
		/*
		 * start = "http://en.wikipedia.org/wiki/Robot"; end =
		 * "http://en.wikipedia.org/wiki/EMIEW";
		 */
		/*
		 * start="http://en.wikipedia.org/wiki/Library_and_Information_Science";
		 * end="http://en.wikipedia.org/wiki/Urticina_lofotensis";
		 */
		// start = FrequencyCollector.getRandomPage();
		// end = FrequencyCollector.getRandomPage();

		start = "http://en.wikipedia.org/wiki/Issac_newton";
		end = "http://en.wikipedia.org/wiki/Apple";

		if (args.length >= 2) {
			start = "http://en.wikipedia.org/wiki/" + args[0];
			end = "http://en.wikipedia.org/wiki/" + args[1];
		}
		long startTime = System.currentTimeMillis();
		int workersNumber=8;
		KeywordTraverserThread test = new KeywordTraverserThread(start, end,workersNumber);
		long endTime = System.currentTimeMillis();
		System.out.println("Found target in " + test.traverse() + " steps.");
		test.printMetrics();
		test.printPath();
		System.out.println("Total time: " + (endTime - startTime));
	}

}
